import axios, { type AxiosRequestConfig } from 'axios'
import { MsgError, MsgAlert } from '@/utils/message'
import type { NProgress } from 'nprogress'
import type { Ref } from 'vue'
import type { Result } from '@/request/Result'
import useStore from '@/stores'
import router from '@/router'

import { ref, type WritableComputedRef } from 'vue'

const axiosConfig = {
  baseURL: '/aibi/api',
  withCredentials: false,
  timeout: 60000,
  headers: {}
}

/**
 *  登陆失效的code码
 *  未能读取到有效Token
 *  NOT_TOKEN = 11011,
 *
 *  token 无效
 *  INVALID_TOKEN = 11012,
 *
 *  token 已过期
 *  TOKEN_TIMEOUT = 11013,
 *
 *  token 已被顶下线
 *  BE_REPLACED = 11014,
 *
 *  token 已被踢下线
 *  KICK_OUT = 11015,
 *
 *  已被冻结
 *  NOT_VALUE_EXPIRE = 11016
 *
 * */
const expireCode = [ 11011, 11012, 11013, 11014, 11015, 11016 ]



const instance = axios.create(axiosConfig)

/* 设置请求拦截器 */
instance.interceptors.request.use(
  (config: AxiosRequestConfig | any) => {
    if (config.headers === undefined) {
      config.headers = {}
    }
    const { user } = useStore()
    // token传给maxkb服务端
    const authorization = config.headers['AUTHORIZATION'] ? config.headers['AUTHORIZATION'] : user.getToken()
    if (authorization) {
      config.headers['AUTHORIZATION'] = `${authorization}`
    }
    return config
  },
  (err: any) => {
    return Promise.reject(err)
  }
)

//设置响应拦截器
instance.interceptors.response.use(
  (response: any) => {
    if (response.data) {
      if (expireCode.includes(response.data.code)) {
        // token失效 退出登录
        localStorage.removeItem('dada-tenantId');
        localStorage.removeItem('dadaTenantId');
        localStorage.removeItem('dadaToken');
        localStorage.removeItem('token');
        document.cookie = 'token=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;';
        // token 已被顶下线 BE_REPLACED = 11014,
        if (response.data.code === 11014) {
          MsgAlert( '系统通知', '您的账号已在另一设备上登录，当前设备上的会话失效，请重新登陆',
            {
              confirmButtonText: '确定',
              closeOnClickModal: false,
              showClose: false
            }
          )
          .then(() => {
              router.push({ name: 'index' })
          })
          return
        }
        router.push({ name: 'index' })
        return
      }
      if (response.data.code !== 200 && !(response.data instanceof Blob)) {
        MsgError(response.data.msg)
        return;
      }
    }
    return response.data
  },
  (err: any) => {
    console.log(err)
    const errCode = ['ECONNABORTED']
    if (errCode.includes(err.code)) {
      MsgError(err.message)
      console.error(err)
    }
    return Promise.reject(err)
  }
)

export const request = instance


/* 简化请求方法，统一处理返回结果，并增加loading处理，这里以{success,data,message}格式的返回值为例，具体项目根据实际需求修改 */
const promise: (
  request: Promise<any>,
  loading?: NProgress | Ref<boolean> | WritableComputedRef<boolean>
) => Promise<Result<any>> = (request, loading = ref(false)) => {
  return new Promise((resolve, reject) => {
    if ((loading as NProgress).start) {
      ;(loading as NProgress).start()
    } else {
      ;(loading as Ref).value = true
    }
    request
      .then((response) => {
        // blob类型的返回状态是response.status
        if (response.status === 200) {
          resolve(response?.data || response)
        } else {
          reject(response?.data || response)
        }
      })
      .catch((error) => {
        reject(error)
      })
      .finally(() => {
        if ((loading as NProgress).start) {
          ;(loading as NProgress).done()
        } else {
          ;(loading as Ref).value = false
        }
      })
  })
}

/**
 * 发送get请求   一般用来请求资源
 * @param url    资源url
 * @param params 参数
 * @param loading loading
 * @param headers 请求头
 * @param timeout 超时时间
 * @returns 异步promise对象
 */
export const get: (
  url: string,
  params?: unknown,
  loading?: NProgress | Ref<boolean>,
  headers?: any,
  timeout?: number
) => Promise<Result<any>> = (
  url: string,
  params: unknown,
  loading?: NProgress | Ref<boolean>,
  headers?: any,
  timeout?: number,
) => {
  return promise(request({ url: url, method: 'get', params, headers, timeout }), loading)
}

/**
 * faso post请求 一般用来添加资源
 * @param url    资源url
 * @param params 参数
 * @param data   添加数据
 * @param loading loading
 * @param headers 请求头
 * @param timeout 超时时间
 * @returns 异步promise对象
 */
export const post: (
  url: string,
  data?: unknown,
  params?: unknown,
  loading?: NProgress | Ref<boolean>,
  headers?: any,
  timeout?: number
) => Promise<Result<any> | any> = (url, data, params, loading, headers, timeout) => {
  return promise(request({ url: url, method: 'post', data, params, headers, timeout }), loading)
}

/**|
 * 发送put请求 用于修改服务器资源
 * @param url     资源地址
 * @param params  params参数地址
 * @param data    需要修改的数据
 * @param loading 进度条
 * @returns
 */
export const put: (
  url: string,
  data?: unknown,
  params?: unknown,
  loading?: NProgress | Ref<boolean>,
  timeout?: number
) => Promise<Result<any>> = (url, data, params, loading, timeout) => {
  return promise(request({ url: url, method: 'put', data, params, timeout }), loading)
}

/**
 * 删除
 * @param url     删除url
 * @param params  params参数
 * @param loading 进度条
 * @returns
 */
export const del: (
  url: string,
  params?: unknown,
  data?: unknown,
  loading?: NProgress | Ref<boolean>,
  timeout?: number
) => Promise<Result<any>> = (url, params, data, loading, timeout) => {
  return promise(request({ url: url, method: 'delete', params, data, timeout }), loading)
}

/**
 * 流处理
 * @param url  url地址
 * @param data 请求body
 * @returns
 */
export const postStream: (url: string, data?: unknown) => Promise<Result<any> | any> = (
  url,
  data
) => {
  const { user } = useStore()
  const token = user.getToken()
  const language = user.getLanguage()
  const headers: HeadersInit = { 'Content-Type': 'application/json' }
  if (token) {
    headers['AUTHORIZATION'] = `${token}`
  }
  headers['Accept-Language'] = `${language}`
  return fetch(url, {
    method: 'POST',
    body: data ? JSON.stringify(data) : undefined,
    headers: headers
  })
}

export const exportExcel: (
  fileName: string,
  url: string,
  params: any,
  loading?: NProgress | Ref<boolean>
) => Promise<any> = (
  fileName: string,
  url: string,
  params: any,
  loading?: NProgress | Ref<boolean>
) => {
  return promise(request({ url: url, method: 'get', params, responseType: 'blob' }), loading).then(
    (res: any) => {
      if (res) {
        const blob = new Blob([res], {
          type: 'application/vnd.ms-excel'
        })
        const link = document.createElement('a')
        link.href = window.URL.createObjectURL(blob)
        link.download = fileName
        link.click()
        //释放内存
        window.URL.revokeObjectURL(link.href)
      }
      return true
    }
  )
}

export const exportFile: (
  fileName: string,
  url: string,
  params: any,
  loading?: NProgress | Ref<boolean>
) => Promise<any> = (
  fileName: string,
  url: string,
  params: any,
  loading?: NProgress | Ref<boolean>
) => {
  return promise(request({ url: url, method: 'get', params, responseType: 'blob' }), loading).then(
    (res: any) => {
      if (res) {
        const blob = new Blob([res], {
          type: 'application/octet-stream'
        })
        const link = document.createElement('a')
        link.href = window.URL.createObjectURL(blob)
        link.download = fileName
        link.click()
        //释放内存
        window.URL.revokeObjectURL(link.href)
      }
      return true
    }
  )
}

export const exportExcelPost: (
  fileName: string,
  url: string,
  params: any,
  data: any,
  loading?: NProgress | Ref<boolean>
) => Promise<any> = (
  fileName: string,
  url: string,
  params: any,
  data: any,
  loading?: NProgress | Ref<boolean>
) => {
  return promise(
    request({
      url: url,
      method: 'post',
      params, // 查询字符串参数
      data, // 请求体数据
      responseType: 'blob'
    }),
    loading
  ).then((res: any) => {
    if (res) {
      const blob = new Blob([res], {
        type: 'application/vnd.ms-excel'
      })
      const link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = fileName
      link.click()
      // 释放内存
      window.URL.revokeObjectURL(link.href)
    }
    return true
  })
}

export const download: (
  url: string,
  method: string,
  data?: any,
  params?: any,
  loading?: NProgress | Ref<boolean>
) => Promise<any> = (
  url: string,
  method: string,
  data?: any,
  params?: any,
  loading?: NProgress | Ref<boolean>
) => {
  return promise(request({ url: url, method: method, data, params, responseType: 'blob' }), loading)
}

export const  getHeaders = ()=> {}

export default instance
